#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lex.h"
#include "symbol.h"
#include "tools.h"

void lexicalAnalysis(char *file_input, char *file_output) {
    // 打开文件
    FILE *fp_in, *fp_out;
    if ((fp_in = fopen(file_input, "r")) == NULL) {
        printf("File open error!\n");
        exit(-1);
    }
    if ((fp_out = fopen(file_output, "w")) == NULL) {
        printf("File open error!\n");
        exit(-1);
    }

    // 符号表初始化
    table_global = (Table *)malloc(sizeof(Table));
    table_global->top_list = -1;
    table_global->top_zone = -1;
    memset(table_global->zone, 0, sizeof(table_global->zone));
    register_cnt = 0;

    // 读入分析
    char ch;
    memset(hold, '\0', sizeof(hold));
    while(1) {
        // 跳过空白字符
        while (isBlank(ch = fgetc(fp_in)));
        // 文件结束判断
        if (ch == EOF) {
            break;
        }

        // 数字判断
        else if (isDigit(ch)) {
            // 十进制
            if (isNonZeroDigit(ch)) {
                hold[0] = ch;
                for (int i=1; isDigit(ch = fgetc(fp_in)); i++) {
                    hold[i] = ch;
                }
                fprintf(fp_out, "DecNumber(%s)\n", hold);
                memset(hold, '\0', sizeof(hold));     // 重置hold
                ungetc(ch, fp_in);
            }
            // 八进制或十六进制
            else {
                ch = fgetc(fp_in);
                // 十六进制
                if (ch == 'x' || ch == 'X') {
                    char temp = ch;
                    for (int i=0; isHexDigit(ch = fgetc(fp_in)); i++) {
                        hold[i] = ch;
                    }
                    if (!isHexDigit(hold[0])) {
                        // 非十六进制数
                        fprintf(fp_out, "OctNumber(0)\n");
                        ungetc(ch, fp_in);
                        ungetc(temp, fp_in);
                    }
                    else {
                        fprintf(fp_out, "HexNumber(%s)\n", hold);
                        memset(hold,'\0',sizeof(hold));     // 重置hold
                        ungetc(ch, fp_in);
                    }
                }
                // 八进制
                else if (isOctalDigit(ch)) {
                    hold[0] = ch;
                    for (int i=1; isOctalDigit(ch = fgetc(fp_in)); i++) {
                        hold[i] = ch;
                    }
                    fprintf(fp_out, "OctNumber(%s)\n", hold);
                    memset(hold,'\0',sizeof(hold));     // 重置hold
                    ungetc(ch, fp_in);
                } 
                // 零和其他
                else {
                    fprintf(fp_out, "OctNumber(0)\n");
                    ungetc(ch, fp_in);
                }
            }
        }

        // 标识符(关键字)判断
        else if (isLetter(ch) || isUnderLine(ch)) {
            hold[0] = ch;
            for (int i=1; isDigit(ch = fgetc(fp_in)) || isLetter(ch) || isUnderLine(ch); i++) {
                hold[i] = ch;
            }
            char token[128];
            memset(token, '\0', sizeof(token));
            // 关键字判断
            strcpy(token, FindKeywords(hold));
            if ((strcmp(token, "")) != 0) {
                fprintf(fp_out, "%s\n", token);
            }
            else {
                fprintf(fp_out, "Ident(%s)\n", hold);
            }
            memset(hold, '\0', sizeof(hold));     // 重置hold
            ungetc(ch, fp_in);
        }

        // 特殊符号判断
        else if (ch == '=') {
            ch = fgetc(fp_in);
            if (ch == '=') {
                fprintf(fp_out, "Eq\n");
            } else {
                fprintf(fp_out, "Assign\n");
                ungetc(ch, fp_in);
            }
        }
        else if (ch == '>') {
            ch = fgetc(fp_in);
            if (ch == '=') {
                fprintf(fp_out, "GreatEq\n");
            }
            else {
                fprintf(fp_out, "Great\n");
                ungetc(ch, fp_in);
            }
        }
        else if (ch == '<') {
            ch = fgetc(fp_in);
            if (ch == '=') {
                fprintf(fp_out, "LessEq\n");
            }
            else {
                fprintf(fp_out, "Less\n");
                ungetc(ch, fp_in);
            }
        }
        else if (ch == '&') {
            ch = fgetc(fp_in);
            if (ch == '&') {
                fprintf(fp_out, "And\n");
            }
            else {
                exit(1);
            }
        }
        else if (ch == '|') {
            ch = fgetc(fp_in);
            if (ch == '|') {
                fprintf(fp_out, "Or\n");
            }
            else {
                exit(1);
            }
        }
        else if (ch == '!') {
            ch = fgetc(fp_in);
            if (ch == '=') {
                fprintf(fp_out, "NotEq\n");
            }
            else {
                fprintf(fp_out, "Rev\n");
                ungetc(ch, fp_in);
            }
        }
        else if (ch == ';') {
            fprintf(fp_out, "Semicolon\n");
        }
        else if (ch == ',') {
            fprintf(fp_out, "Comma\n");
        }
        else if (ch == '(') {
            fprintf(fp_out, "LPar\n");
        }
        else if (ch == ')') {
            fprintf(fp_out, "RPar\n");
        }
        else if (ch == '{') {
            fprintf(fp_out, "LBrace\n");
        }
        else if (ch == '}') {
            fprintf(fp_out, "RBrace\n");
        }
        else if (ch == '+') {
            fprintf(fp_out, "Plus\n");
        }
        else if (ch == '-') {
            fprintf(fp_out, "Minus\n");
        }
        else if (ch == '*') {
            fprintf(fp_out, "Mult\n");
        }
        else if (ch == '/') {
            fprintf(fp_out, "Div\n");
        }
        else if (ch == '%') {
            fprintf(fp_out, "Rem\n");
        }

        // 词法错误
        else {
            exit(1);
        }
    }
    
    // 关闭文件
    fclose(fp_in);
    fclose(fp_out);
}

char* FindKeywords(char str[]) {
    int i;
    // printf("====%d====\n", sizeof(keywords) / sizeof(keywords[0]));
    for (i=0; i<sizeof(keywords)/sizeof(keywords[0]); i++) {
        if (strcmp(keywords[i], str) == 0) {
            // printf("====%s====\n", keywordsToken[i]);
            return keywordsToken[i];
        }
    }
    return "";
}